package utils

import (
	middleware "KumquatDrivesServices/Middleware"
	"KumquatDrivesServices/enums"
	"KumquatDrivesServices/global"
	"KumquatDrivesServices/model"
	"encoding/json"
	"errors"
	"fmt"
	"github.com/gin-gonic/gin"
	"github.com/nfnt/resize"
	"github.com/sirupsen/logrus"
	"gorm.io/gorm"
	"image"
	"image/jpeg"
	"image/png"
	"math/rand"
	"os"
	"path/filepath"
	"strings"
	"time"
)

var seededRand = rand.New(rand.NewSource(time.Now().UnixNano()))

func GetUserId(c *gin.Context) model.SnowflakeIdType {
	u, bol := c.Get(middleware.SetKey)
	if !bol {
		return 0
	}
	userId, ok := u.(model.SnowflakeIdType)
	if !ok {
		logrus.Error("user_id is not int")
		return 0
	}
	return userId
}

func RandomString(length int) string {
	//goland:noinspection SpellCheckingInspection
	const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
		"abcdefghijklmnopqrstuvwxyz" +
		"0123456789"
	if length < 1 {
		return ""
	}
	var b strings.Builder
	b.Grow(length)
	for i := 0; i < length; i++ {
		b.WriteByte(charset[seededRand.Intn(len(charset))])
	}
	return b.String()
}

// Rename 返回新的文件名
func Rename(fileName string) string {
	ext := filepath.Ext(fileName)
	return fileName[:len(fileName)-len(ext)] + "_" + RandomString(5) + ext
}

// PathExists 检查给定的路径是否存在
func PathExists(path string) bool {
	_, err := os.Stat(path)
	if os.IsNotExist(err) {
		return false
	}
	return true
}

// CreatePath 创建目录
func CreatePath(path string) error {
	// 确保路径格式化正确
	path = filepath.Clean(path)
	dir := filepath.Dir(path)

	// 检查目录是否存在
	if _, err := os.Stat(dir); os.IsNotExist(err) {
		// 如果目录不存在，则创建它
		if err = os.MkdirAll(dir, 0755); err != nil {
			return err
		}
	}

	return nil
}
func CompressSingleImage(inputPath, outputPath string, width int) error {
	// 打开输入图片文件
	file, err := os.Open(inputPath)
	if err != nil {
		return err
	}
	defer file.Close()

	// 解码图片
	img, _, err := image.Decode(file)
	if err != nil {
		return err
	}

	// 获取原始图片的尺寸
	bounds := img.Bounds()
	originalWidth := bounds.Max.X - bounds.Min.X
	originalHeight := bounds.Max.Y - bounds.Min.Y
	// 计算新的高度以保持宽高比
	newHeight := width * originalHeight / originalWidth
	// 使用nfnt/resize库进行图片缩放
	resizedImg := resize.Resize(uint(width), uint(newHeight), img, resize.Lanczos3)

	// 创建输出文件
	outFile, err := os.Create(outputPath)
	if err != nil {
		return err
	}
	defer outFile.Close()

	// 根据图片格式进行编码并保存压缩后的图片
	switch strings.ToLower(strings.Split(filepath.Ext(outputPath), ".")[1]) {
	case "jpg", "jpeg":
		err = jpeg.Encode(outFile, resizedImg, &jpeg.Options{Quality: 50})
	case "png":
		err = png.Encode(outFile, resizedImg)
	default:
		return fmt.Errorf("unsupported file format")
	}
	if err != nil {
		return err
	}
	return nil
}

// GetBaseNameWithoutExt 提取文件名去掉后缀的部分
func GetBaseNameWithoutExt(filePath string) string {
	fileName := filepath.Base(filePath)
	return strings.TrimSuffix(fileName, filepath.Ext(fileName))
}

// CheckSameNameFileOrDir 检查同级目录是否存在同名文件或目录，如果存在，则返回true，否则返回false
func CheckSameNameFileOrDir(filePid, userId model.SnowflakeIdType, filename string, IsFolderType bool) (bool, error) {
	var count int64 = 0
	query := global.DB.Model(&model.FileModel{}).Where("file_pid=? and user_id=? and file_name=? and is_folder=? and del_flag=?",
		filePid, userId, filename, IsFolderType, enums.Normal)
	if err := query.Count(&count).Error; err != nil && errors.Is(err, gorm.ErrRecordNotFound) {
		return false, err
	}
	return count > 0, nil
}

// SetDownloadHeader 设置下载所需的响应头
func SetDownloadHeader(FileName string, c *gin.Context) {
	//表示文件流
	c.Header("Content-Type", "application/octet-stream")
	//设置下载名字
	c.Header("Content-Disposition", fmt.Sprintf("attachment;filename=%s", FileName))
	//设置传输编码形式
	c.Header("Content_Transfer-Encoding", "binary")
}
func FindAllSubFolderFileList(userId, fileId model.SnowflakeIdType, delFlag int) ([]model.FileModel, error) {
	var fileList []model.FileModel
	/*	var find func(fileList *[]model.FileModel, userId, fileId model.SnowflakeIdType, delFlag int) error
		find = func(fileList *[]model.FileModel, userId, fileId model.SnowflakeIdType, delFlag int) error {
			var findFileList []model.FileModel
			if err := global.DB.Where("file_pid=? and user_id=? and del_flag=?", fileId, userId, delFlag).Find(&findFileList).Error; err != nil {
				return err
			}
			for _, file := range findFileList {
				_ = find(fileList, userId, file.ID, delFlag)
				*fileList = append(*fileList, file)
			}
			return nil
		}
		if err := find(&fileList, userId, fileId, delFlag); err != nil {
			return nil, err
		}*/
	query := `WITH RECURSIVE SubFiles AS (
    SELECT *
    FROM file_models
    WHERE file_pid = ? AND user_id = ? AND del_flag = ?
    UNION ALL
    SELECT f.*
    FROM file_models f
             INNER JOIN SubFiles s ON f.file_pid = s.id
    )
    SELECT *
	FROM SubFiles;`
	if err := global.DB.Raw(query, fileId, userId, delFlag).Scan(&fileList).Error; err != nil {
		return fileList, err
	}
	return fileList, nil
}
func GetFileTree(userid model.SnowflakeIdType, fileInfo model.FileModel) ([]*FileTree, error) {
	if fileInfo.IsFolder != enums.Folder {
		return nil, errors.New("FileInfo is not a folder")
	}
	findFileList, err := FindAllSubFolderFileList(userid, fileInfo.ID, enums.Normal)
	if err != nil {
		return nil, err
	}
	findFileList = append(findFileList, fileInfo)
	return BuildFileTree(findFileList), nil
}
func CacheDownloadIdOfFileInfo(DownloadId string, fileTree []*FileTree) error {
	if DownloadId == "" {
		return fmt.Errorf("downloadId为空")
	}
	Key := fmt.Sprintf("downloadId_%s", DownloadId)
	fileTreeByte, err := json.Marshal(fileTree)
	if err != nil {
		return err
	}
	if err = global.Redis.Set(Key, string(fileTreeByte), time.Minute).Err(); err != nil {
		return err
	}
	return nil
}
func GetDownloadIdOfFileInfo(DownloadId string) ([]*FileTree, error) {
	if DownloadId == "" {
		return nil, fmt.Errorf("downloadId为空")
	}
	Key := fmt.Sprintf("downloadId_%s", DownloadId)
	fileTreeStr, err := global.Redis.Get(Key).Result()
	if err != nil {
		return nil, err
	}
	var fileTree []*FileTree
	if err = json.Unmarshal([]byte(fileTreeStr), &fileTree); err != nil {
		return nil, err
	}
	return fileTree, nil
}
